iT邦幫忙

2025 iThome 鐵人賽

DAY 29
0
自我挑戰組

《轉職學習日記:JavaScript × Node.js × TypeScript × Docker × AWS ECS》系列 第 29

Day29 - 持續成長學習藍圖 - Docker(Dockerfile)

  • 分享至 

  • xImage
  •  

昨天先用 docker run 玩了一圈,今天真的把我的 TS + Express + Prisma 專案打包進容器。
目標很明確:node:18-alpine 當基底,寫 Dockerfile、加 .dockerignore,然後在容器中 npm installnpm run dev 跑起來


1) Dockerfile 的四個關鍵指令

  • FROM:基底映像(今天用 node:18-alpine,小又夠用)
  • COPY:把檔案丟進映像
  • RUN:在建置階段執行指令(例如安裝套件)
  • CMD:容器啟動後要執行什麼(例如 npm run dev

2) 專案預期結構(簡化)

ts-todo-api/
├─ src/
│  └─ index.ts
├─ prisma/
│  └─ schema.prisma
├─ package.json
├─ tsconfig.json
└─ .env            # 若有(ex: DATABASE_URL)

之前 Day 25 你應該已經有 npm run dev(用 ts-node-dev 或 nodemon)。


3) 建立 .dockerignore(超重要)

避免把不需要的東西塞進映像,影響建置速度與大小:

node_modules
dist
.git
Dockerfile
docker-compose*.yml
.env
npm-debug.log
pnpm-lock.yaml
yarn.lock
.prisma
dev.db

之後會用 Compose 把 DB 變成獨立容器;現在先避免把本機檔案黏進 image。


4) 撰寫 Dockerfile(開發版)

在專案根目錄新增 Dockerfile

# 1. 基底映像:輕量的 Node.js
FROM node:18-alpine

# 2. 建置內的工作目錄
WORKDIR /app

# 3. 先複製相依檔、安裝(利用快取)
COPY package*.json ./
RUN npm ci

# 4. 再複製其他原始碼
COPY . .

# 5. 設定環境(開發模式)
ENV NODE_ENV=development

# 6. 對外開放的埠(Express 預設 3000)
EXPOSE 3000

# 7. 啟動命令:先做 Prisma 需要的 generate(如果有用),再跑 dev
#    你也可以改成 `npm run dev`(看你專案 script)
CMD ["sh", "-c", "npx prisma generate || true && npm run dev"]

為什麼這樣寫?

  • COPY package*.jsonRUN npm ci:善用快取,程式碼變了但依賴沒變時,建置會快很多。
  • CMDsh -c:我順手加了 npx prisma generate 以防你用到 Prisma。|| true 讓沒有 Prisma 也不會中斷。
  • EXPOSE 3000:只是文件化標示,實際暴露要用 -p 或 Compose。

若你用 ts-node-dev,在 WSL/Docker 上若檔案變動偵測不到,可加環境變數:
ENV CHOKIDAR_USEPOLLING=true(視你的 watcher 而定)


5) 建置與啟動

# 建置映像
docker build -t ts-todo-api:dev .

# 啟動容器(把主機 3000 映射到容器 3000)
docker run --name ts-todo -p 3000:3000 --rm ts-todo-api:dev

打開 http://localhost:3000(或 /todos),看到熟悉的回應就成功了 🎉

想看日誌:docker logs -f ts-todo
想進容器:docker exec -it ts-todo sh


6) 小技巧:讓開發更順(可選)

如果你想要邊改碼邊自動重啟(Hot Reload),可以把原始碼用 Volume 掛進去,並確保你的 npm run dev 會 watch 檔案:

docker run --name ts-todo \
  -p 3000:3000 \
  -v "$PWD:/app" \
  -v /app/node_modules \
  --env CHOKIDAR_USEPOLLING=true \
  --rm ts-todo-api:dev

說明:

  • -v "$PWD:/app":把本機專案掛進容器(即時看到變動)
  • -v /app/node_modules:避免把本機空的 node_modules 覆蓋容器內的(這是常見坑)
  • CHOKIDAR_USEPOLLING=true:有些 watcher 在容器內需要 polling 才偵測到變動

7) 常見坑 & 排錯筆記

  • 容器起來了但瀏覽器連不到

    • 檢查 docker run -p 3000:3000 有沒有加
    • Express 設定通常 app.listen(3000) 就會綁 0.0.0.0(OK)
  • 建置很慢、image 很大

    • 一定要加 .dockerignore
    • COPY package*.jsonnpm ci,利用快取
  • Prisma 找不到 Client

    • 在 CMD 或 Entrypoint 先 npx prisma generate
  • 改碼沒反應

    • 使用 volume -v "$PWD:/app"
    • watcher 需要 CHOKIDAR_USEPOLLING=true(依你的工具而定)

🎯 今日收穫 / 心得

今天是第一次把自己的 TS API「打包進貨櫃」:

  • 了解 FROM/COPY/RUN/CMD 的最小組合
  • node:18-alpine 開到最小可用的 Node 環境
  • .dockerignore 真的超重要,建置速度差很多
  • 在容器裡 npm install + npm run dev 順利跑起來,看到 http://localhost:3000 的瞬間滿滿成就感 ✨

上一篇
Day28 - 持續成長學習藍圖 - Docker
系列文
《轉職學習日記:JavaScript × Node.js × TypeScript × Docker × AWS ECS》29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言